package com.baicaoyuan.web.service;

import com.baicaoyuan.web.common.MsgUtil;
import com.baicaoyuan.web.common.PlatformIdConfig;
import com.baicaoyuan.web.common.StringUtils;
import com.baicaoyuan.web.common.TimeUtils;
import com.baicaoyuan.web.enums.BusinessStatusEnum;
import com.baicaoyuan.web.enums.BusinessTypeEnum;
import com.baicaoyuan.web.model.JzzBusinessDO;
import com.baicaoyuan.web.model.JzzCurveDO;
import com.baicaoyuan.web.model.JzzUserDO;
import com.baicaoyuan.web.model.UserDO;
import com.baicaoyuan.web.repository.JzzBusinessRepository;
import com.baicaoyuan.web.repository.JzzCurveRepository;
import com.baicaoyuan.web.repository.JzzUserRepository;
import com.baicaoyuan.web.repository.UserRepository;
import com.baicaoyuan.web.request.br.*;
import com.baicaoyuan.web.response.JzzBusinessDetailsResponse;
import com.baicaoyuan.web.response.JzzBusinessMyResponse;
import com.baicaoyuan.web.response.JzzBusinessResponse;
import com.baicaoyuan.web.response.JzzDoneBusinessResponse;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.hash.Hashing;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 功能描述：
 *
 * @author 罗富祥
 * 创建时间： 2018/1/4
 */
@Service
public class JzzBusinessService {


    @Autowired
    JzzBusinessRepository jzzBusinessRepository;

    @Autowired
    JzzUserRepository jzzUserRepository;

    @Autowired
    UserRepository userRepository;

    @Autowired
    JzzCurveRepository jzzCurveRepository;

    @Autowired
    PlatformIdConfig platformIdConfig;


    @Autowired
    UserService userService;

    private static final String MD5_KEY = "luofuxiang";


    private String no(Long userId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return userId.toString() + "-" + sdf.format(new Date());
    }

    private String md5(JzzBusinessDO businessDo) {
        String content = String.format("sourceUserId:%s,targetUserId:%s,jzzPrice:%s,jzzNumber:%s,id:%s,",
                businessDo.getSourceUserId(),
                businessDo.getTargetUserId(),
                businessDo.getJzzPrice(),
                businessDo.getJzzNumber(),
                businessDo.getId());

        content += "key:" + MD5_KEY;

        String r = Hashing.md5().newHasher().putString(content, Charsets.UTF_8).hash().toString();
        System.out.println(content + ":: " + r);
        return r;
    }

    //获取一个用户正在售卖的数量
    private BigDecimal onSale(Long saleUserId) {
        List<String> status = Arrays.asList(BusinessStatusEnum.CREATE.getStatus(), BusinessStatusEnum.LOCK.getStatus(), BusinessStatusEnum.UPLOAD_VOUCHER.getStatus());

        List<JzzBusinessDO> businesses = jzzBusinessRepository.findBySourceUserIdAndStatusIn(saleUserId, status);
        BigDecimal result = new BigDecimal(0);
        for (JzzBusinessDO i : businesses) {
            result = result.add(i.getJzzNumber());
        }
        return result;
    }

    private boolean check(JzzBusinessDO businessDo, String md5) {
        String s = md5(businessDo);
        System.out.println("-------:id:" + businessDo.getId() + "now md5" + s + "check :" + md5);
        return s.equals(md5);
    }

    public JzzBusinessDO toBuy(BJzzToBuy bJzzToBuy, Long currentUserId) throws Exception {
        List<JzzBusinessDO> locks = jzzBusinessRepository.findAllByTargetUserIdAndStatus(currentUserId, BusinessStatusEnum.LOCK.getStatus());
        if (locks.size() > 0) {
            throw new Exception("您的账户下已经存在锁定的订单，请完成交易后继续购买！或取消原有订单再继续");
        }
        JzzBusinessDO business = jzzBusinessRepository.findOne(bJzzToBuy.getId());
        if (business.getStatus().equals(BusinessStatusEnum.LOCK.getStatus())) {
            throw new Exception("已被购买，锁定！请刷新列表！");
        }
        if (business.getStatus().equals(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus())) {
            throw new Exception("已被购买，锁定！请刷新列表！");
        }
        if (business.getStatus().equals(BusinessStatusEnum.DONE.getStatus())) {
            throw new Exception("已被购买，交易结束，请刷新列表！");
        }
        if (business.getSourceUserId().longValue() == currentUserId.longValue()) {
            throw new Exception("无法购买自己的订单！");
        }
        business.setTargetUserId(bJzzToBuy.getUserId());

        BigDecimal price = getCurrentPrice();
        business.setJzzPrice(price);
        business.setJzzTotalPrice(business.getJzzNumber().multiply(price));
        business.setStatus(BusinessStatusEnum.LOCK.getStatus());
        business.setUpdateTime(TimeUtils.getCurrentTime());
        String md5 = md5(business);
        System.out.println("-------:id:" + business.getId() + "md5" + md5);
        business.setMd5(md5);
        return jzzBusinessRepository.save(business);
    }

    /**
     * 上传打款凭证
     *
     * @param request
     * @return
     * @throws Exception
     */
    public boolean toBuyUploadVoucher(BJzzToBuyUploadVoucher request) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(request.getId());
        if (request.getUserId().longValue() != business.getTargetUserId()) {
            throw new Exception("该订单实际购买人不是登录用户，存在异常，请联系客服！");
        }
        if (business.getStatus().equals(BusinessStatusEnum.LOCK.getStatus())) {
            business.setPayVoucher(request.getPayVoucher());
            business.setStatus(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus());
            return jzzBusinessRepository.save(business) != null;
        } else {
            throw new Exception("订单状态异常，请刷新页面或者请联系客服人员！");
        }
    }

    /**
     * 发送md5码给买家
     *
     * @param request
     * @throws Exception
     */
    public void sendMa(BJzzToBuy request) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(request.getId());
        if (request.getUserId().longValue() != business.getSourceUserId()) {
            throw new Exception("该订单实际售卖人不是登录用户，存在异常，请联系客服！");
        }
        if (!business.getStatus().equals(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus())) {
            throw new Exception("买家还没有上传凭证，无法发送提取码！");
        }
        UserDO user = userRepository.getOne(business.getTargetUserId());
        MsgUtil.getBusinessMa(user.getTelephone(), business.getNo(), business.getMd5());
    }

    public void adminSendMa(BJzzToBuy request) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(request.getId());
        if (!business.getStatus().equals(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus())) {
            throw new Exception("买家还没有上传凭证，无法发送提取码！");
        }
        UserDO user = userRepository.getOne(business.getTargetUserId());
        MsgUtil.getBusinessMa(user.getTelephone(), business.getNo(), business.getMd5());
    }

    private BigDecimal getCurrentPrice() {
        JzzCurveDO curve = jzzCurveRepository.findTopOrderByIdDesc();
        BigDecimal price = curve.getPrice();
        return price;
    }

    public boolean toSale(BJzzToSale request) throws Exception {

        JzzBusinessDO business = jzzBusinessRepository.getOne(request.getId());
        if (business.getTargetUserId().longValue() == request.getUserId().longValue()) {
            throw new Exception("请不要自己向自己出售lzb！");
        }
        business.setStatus(BusinessStatusEnum.LOCK.getStatus());
        UserDO user = userRepository.getOne(request.getUserId());
        if (StringUtils.isNullOrEmpty(user.getBank())) {
            throw new Exception("无银行账户信息，请实名认证！");
        }
        JzzUserDO jzzUser = jzzUserRepository.findByUserId(request.getUserId());
        BigDecimal r = business.getJzzNumber().add(business.getServiceCharge());
        if (r.doubleValue() > jzzUser.getJzzNumber().doubleValue()) {
            throw new Exception("您的账号金钟数量不足！");
        }
        business.setPayInfoJson(user.getBank());
        business.setSourceUserId(request.getUserId());


        BigDecimal price = getCurrentPrice();
        business.setJzzPrice(price);
        business.setJzzTotalPrice(business.getJzzNumber().multiply(price));
        business.setUpdateTime(TimeUtils.getCurrentTime());
        String md5 = md5(business);
        System.out.println("-------:id:" + business.getId() + "md5" + md5);
        business.setMd5(md5);

        return jzzBusinessRepository.save(business) != null;
    }

    @Transactional(rollbackFor = Exception.class)
    public void checkDone(BJzzBuySaleCheck request) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(request.getId());
        if (request.getUserId().longValue() != business.getTargetUserId()) {
            throw new Exception("该订单实际购买人不是登录用户，存在异常，请联系客服！");
        }
        if (check(business, request.getMd5().trim())) {
            doBusiness(request.getId());
        } else {
            throw new Exception("核对码错误！");
        }
    }

    /**
     * 完成交易
     *
     * @param id
     */
    private synchronized void doBusiness(Long id) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(id);
        UserDO user = userRepository.getOne(business.getTargetUserId());
        if (1 == user.getType().intValue()) {
            JzzUserDO buyUser = jzzUserRepository.findByUserId(business.getTargetUserId());
            JzzUserDO saleUser = jzzUserRepository.findByUserId(business.getSourceUserId());


            //buyUser.setJzzNumber(buyUser.getJzzNumber().add(business.getJzzNumber()));
            jzzUserRepository.updateJzzNumberCash(buyUser.getUserId(), business.getJzzNumber().multiply(new BigDecimal(-1)));

            //saleUser.setJzzNumber(saleUser.getJzzNumber().subtract(business.getJzzNumber()).subtract(business.getServiceCharge()));
            BigDecimal n = business.getJzzNumber().add(business.getServiceCharge());
            jzzUserRepository.updateJzzNumberCash(saleUser.getUserId(), n);

            jzzUserRepository.save(buyUser);
            jzzUserRepository.save(saleUser);

            business.setFinishedTime(new Timestamp(new Date().getTime()));
            business.setStatus(BusinessStatusEnum.DONE.getStatus());
            jzzBusinessRepository.save(business);
            addServiceCharge(business.getServiceCharge());
        } else {
            throw new Exception("买方非金种子账户！");
        }
    }

    private void addServiceCharge(BigDecimal serviceCharge) {
        Long userId = Long.parseLong(platformIdConfig.getService_charge_user_id());
        JzzUserDO user = jzzUserRepository.findByUserId(userId);
        if (user != null) {
            BigDecimal jzzNumber = user.getJzzNumber().add(serviceCharge);
            user.setJzzNumber(jzzNumber);
            jzzUserRepository.save(user);
        }
    }

    /**
     * 创建买单
     *
     * @param buy
     * @return
     */
    public boolean createBuy(BJzzBuy buy) {
        JzzBusinessDO business = new JzzBusinessDO();

        business.setTargetUserId(buy.getUserId());
        business.setType(BusinessTypeEnum.BUY.getStatus());
        business.setStatus(BusinessStatusEnum.CREATE.getStatus());
        BigDecimal serviceJzz = buy.getJzzNumber().multiply(BigDecimal.valueOf(platformIdConfig.getService_charge()));
        business.setServiceCharge(serviceJzz);
        business.setJzzNumber(buy.getJzzNumber().subtract(serviceJzz));
        business.setNo(no(buy.getUserId()));
        return jzzBusinessRepository.save(business) != null;
    }

    /**
     * 卖方取消订单
     *
     * @param userId
     * @param id
     * @return
     * @throws Exception
     */
    public boolean saleCancel(Long userId, Long id) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(id);

        if (business.getSourceUserId() == userId.longValue()) {
            if (Integer.parseInt(business.getStatus()) >= Integer.parseInt(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus())) {
                throw new Exception("该订单已经上传了打款凭证或者已经成交而无法取消，请联系客服！");
            }
            if (Integer.parseInt(business.getStatus()) == Integer.parseInt(BusinessStatusEnum.LOCK.getStatus())) {
                //如果是锁定状态， 那么30分钟才能取消
                Timestamp lockTime = business.getUpdateTime();
                boolean isOvertime = TimeUtils.checkOvertimeNow(lockTime, 35);
                if (!isOvertime) {
                    throw new Exception("订单已经被买家锁定，等待买家付款，35分钟内无法取消！");
                }
            }
            business.setStatus(BusinessStatusEnum.CANCEL.getStatus());
            return jzzBusinessRepository.save(business) != null;
        } else {
            throw new Exception("不属于登录用户的订单，无法取消！");
        }
    }

    public JzzBusinessDetailsResponse details(Long id) {
        JzzBusinessDO jzzBusiness = jzzBusinessRepository.getOne(id);
        JzzBusinessDetailsResponse response = new JzzBusinessDetailsResponse();
        BeanUtils.copyProperties(jzzBusiness, response);
        return response;
    }

    public boolean buyCancel(Long userId, Long id) throws Exception {
        JzzBusinessDO business = jzzBusinessRepository.getOne(id);
        if (business.getTargetUserId() == userId.longValue()) {
            if (Integer.parseInt(business.getStatus()) <= Integer.parseInt(BusinessStatusEnum.UPLOAD_VOUCHER.getStatus())) {
                business.setStatus(BusinessStatusEnum.CREATE.getStatus());
                business.setTargetUserId(null);
                business.setJzzTotalPrice(null);
                business.setJzzPrice(null);
                business.setPayInfoJson(null);
                business.setPayVoucher(null);
                return jzzBusinessRepository.save(business) != null;
            } else {
                throw new Exception("该订单已经成交， 无法取消！");
            }
        } else {
            throw new Exception("不属于登录用户的订单，无法取消！");
        }
    }

    /**
     * 创建卖单
     * 扣除了手续费（按比例的金种子）
     *
     * @param sale
     * @return
     */
    public synchronized boolean createSale(BJzzSale sale) throws Exception {
        boolean result;

        JzzUserDO user = jzzUserRepository.findByUserId(sale.getUserId());
        if (user.getJzzNumber().compareTo(sale.getJzzNumber()) < 0) {
            throw new Exception("售卖数量大于拥有数量， 请重新填写！");
        }
        if (user.getJzzNumber().subtract(onSale(sale.getUserId())).compareTo(sale.getJzzNumber()) < 0) {
            throw new Exception("售卖数量大于拥有数量， 请重新填写！");
        }
        UserDO userDO = userRepository.getOne(sale.getUserId());
        if (StringUtils.isNullOrEmpty(userDO.getBank())) {
            throw new Exception("无银行账户信息，请实名认证！");
        }
        JzzBusinessDO business = new JzzBusinessDO();
        BigDecimal serviceJzz = sale.getJzzNumber().multiply(BigDecimal.valueOf(platformIdConfig.getService_charge()));
        business.setServiceCharge(serviceJzz);
        business.setJzzNumber(sale.getJzzNumber().subtract(serviceJzz));
        business.setSourceUserId(sale.getUserId());
        business.setPayInfoJson(userDO.getBank());
        business.setType(BusinessTypeEnum.SALE.getStatus());
        business.setStatus(BusinessStatusEnum.CREATE.getStatus());
        business.setNo(no(sale.getUserId()));
        result = jzzBusinessRepository.save(business) != null;
        return result;
    }

    /**
     * 分页获取买卖列表
     *
     * @param typeEnum
     * @param pageNo
     * @param pageSize
     * @return
     */
    public JzzBusinessResponse getBusiness(BusinessTypeEnum typeEnum, int pageNo, int pageSize) {
        JzzBusinessResponse response = new JzzBusinessResponse();
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);
        List<String> status = Lists.newArrayList();
        status.add(BusinessStatusEnum.CANCEL.getStatus());
        status.add(BusinessStatusEnum.DONE.getStatus());
        Page<JzzBusinessDO> page = jzzBusinessRepository.findAllByTypeAndStatusNotIn(typeEnum.getStatus(), status, pageable);
        switch (typeEnum) {
            case BUY:
                response.setBuys(convert2Buy(page.getContent()));
                response.setPage(page.getTotalPages());
                break;
            case SALE:
                response.setSales(convert2Sale(page.getContent()));
                response.setPage(page.getTotalPages());
                break;
        }
        return response;
    }

    public JzzDoneBusinessResponse getDoneBusiness(Long userId, int pageNo, int pageSize) {
        JzzDoneBusinessResponse response = new JzzDoneBusinessResponse();
        Sort sort = new Sort(Sort.Direction.DESC, "finished_time");
        Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);
        Page<JzzBusinessDO> page = jzzBusinessRepository.queryMyDoneBusiness(BusinessStatusEnum.DONE.getStatus(), userId, pageable);
        response.setSales(convert2Detail(page.getContent()));
        setSign(response.getSales(), userId);
        response.setPage(page.getTotalPages());
        return response;
    }

    private void setSign(List<JzzBusinessDetailsResponse> list, Long userId) {
        for (JzzBusinessDetailsResponse r : list) {
            if (r.getTargetUserId().equals(userId)) {
                r.setSign("+");
            }
            if (r.getSourceUserId().equals(userId)) {
                r.setSign("-");
            }
        }
    }

    public JzzDoneBusinessResponse getAdminBusiness(String status, int pageNo, int pageSize) {
        JzzDoneBusinessResponse response = new JzzDoneBusinessResponse();
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);
        Page<JzzBusinessDO> page = jzzBusinessRepository.findAllByStatus(status, pageable);
        response.setSales(convert2Detail(page.getContent()));
        response.setPage(page.getTotalPages());
        return response;
    }

    public List<JzzBusinessResponse.Sale> convert2Sale(List<JzzBusinessDO> businesses) {
        List<JzzBusinessResponse.Sale> result = new ArrayList<>();
        businesses.stream().forEach(b -> {
            JzzBusinessResponse.Sale sale = new JzzBusinessResponse.Sale();
            BeanUtils.copyProperties(b, sale);
            UserDO user = userRepository.findOne(b.getSourceUserId());
            if (user != null && user.getRealName() != null) {
                String realName = (new StringBuilder(user.getRealName())).replace(1, 2, "*").toString();
                sale.setUserName(realName);
            }
            result.add(sale);
        });
        return result;
    }

    public List<JzzBusinessDetailsResponse> convert2Detail(List<JzzBusinessDO> businesses) {
        List<JzzBusinessDetailsResponse> result = new ArrayList<>();
        businesses.stream().forEach(b -> {
            JzzBusinessDetailsResponse sale = new JzzBusinessDetailsResponse();
            BeanUtils.copyProperties(b, sale);
            if (b.getSourceUserId() != null) {
                sale.setSourceUser(userService.getSimpleUser(b.getSourceUserId()));
            }
            if (b.getTargetUserId() != null) {
                sale.setTargetUser(userService.getSimpleUser(b.getTargetUserId()));
            }
            result.add(sale);
        });
        return result;
    }

    public List<JzzBusinessResponse.Buy> convert2Buy(List<JzzBusinessDO> businesses) {
        List<JzzBusinessResponse.Buy> result = new ArrayList<>();
        businesses.stream().forEach(b -> {
            JzzBusinessResponse.Buy buy = new JzzBusinessResponse.Buy();
            BeanUtils.copyProperties(b, buy);
            UserDO user = userRepository.findOne(b.getTargetUserId());
            if (user != null && user.getRealName() != null) {
                String realName = (new StringBuilder(user.getRealName())).replace(1, 2, "*").toString();
                buy.setUserName(realName);
            }
            result.add(buy);
        });
        return result;
    }

    public List<JzzBusinessMyResponse> getBuyBusinessByUserId(Long userId) {
        return convert2(jzzBusinessRepository.findByTargetUserId(userId));
    }

    public List<JzzBusinessMyResponse> getSaleBusinessByUserId(Long userId) {
        return convert2(jzzBusinessRepository.findBySourceUserId(userId));
    }

    private List<JzzBusinessMyResponse> convert2(List<JzzBusinessDO> business) {
        List<JzzBusinessMyResponse> result = new ArrayList<>();
        for (JzzBusinessDO i : business) {
            JzzBusinessMyResponse r = new JzzBusinessMyResponse();
            BeanUtils.copyProperties(i, r);
            result.add(r);
        }

        return result;
    }
}